package ita.class1.group2.supermarket.common.captain.listener;

import ita.class1.group2.supermarket.common.auth.Realm;
import ita.class1.group2.supermarket.common.auth.SecurityManager;
import ita.class1.group2.supermarket.common.auth.SecurityUtils;
import ita.class1.group2.supermarket.common.captain.CaptainApplication;
import ita.class1.group2.supermarket.common.captain.manager.ContextManager;
import ita.class1.group2.supermarket.common.jms.JmsReceiver;
import ita.class1.group2.supermarket.common.util.ConnectionManager;
import org.apache.log4j.Logger;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * Captain is a similar framework to Spring Boot, and you need to add this listener to your web.xml file before you use it to initialize the Captain service.
 *
 * @author Burgess Li
 * @date 2018/07/19
 */
public class CaptainApplicationListener implements ServletContextListener, ServletRequestListener, HttpSessionListener {

    private static final Logger LOGGER = Logger.getLogger(CaptainApplicationListener.class);

    public static final String START_JMS_RECEIVER = "start-jms-receiver";
    public static final String AUTH_REALM_CLASS = "auth-realm-class";

    private ContextManager contextManager;
    private SecurityUtils securityUtils;

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        Map<String, String> initParams = new HashMap<String, String>();
        LOGGER.info("Captain scanning classes");
        initParams.put(CaptainApplication.MAIN_PACKAGE, sce.getServletContext().getInitParameter(CaptainApplication.MAIN_PACKAGE));
        initParams.put(CaptainApplication.COMMON_PACKAGE, sce.getServletContext().getInitParameter(CaptainApplication.COMMON_PACKAGE));
        CaptainApplication.getInstance().initializeCaptain(initParams);

        boolean startJmsReceiver = false;
        if (sce.getServletContext().getInitParameter(START_JMS_RECEIVER) != null) {
            startJmsReceiver = Boolean.valueOf(sce.getServletContext().getInitParameter(START_JMS_RECEIVER));
        }
        if (startJmsReceiver) {
            LOGGER.info("Initialize jms receiver");
            initializeJMSReceiver();
        }

        LOGGER.info("Initialize context manager");
        contextManager = (ContextManager) CaptainApplication.getInstance().getComponentManager().getBean(ContextManager.class);
        contextManager.initialize(sce.getServletContext());

        if (sce.getServletContext().getInitParameter(AUTH_REALM_CLASS) != null) {
            LOGGER.info("Initialize realms");
            try {
                Realm realm = (Realm) CaptainApplication.getInstance().getComponentManager().getBean(Class.forName(sce.getServletContext().getInitParameter(AUTH_REALM_CLASS)));
                Set<Realm> realms = new HashSet<Realm>();
                realms.add(realm);
                securityUtils = (SecurityUtils) CaptainApplication.getInstance().getComponentManager().getBean(SecurityUtils.class);
                securityUtils.initializeSecurityUtils(new SecurityManager(realms));
            } catch (Exception e) {
                LOGGER.error("Can not initialize realms: " + sce.getServletContext().getInitParameter(AUTH_REALM_CLASS) + ", Message: " + e.toString());
            }
        }


    }

    private void initializeJMSReceiver() {
        JmsReceiver jmsReceiver = (JmsReceiver) CaptainApplication.getInstance().getComponentManager().getBean(JmsReceiver.class);
        jmsReceiver.initializeAllReceiver();
        jmsReceiver.startReceiver();
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        JmsReceiver jmsReceiver = (JmsReceiver) CaptainApplication.getInstance().getComponentManager().getBean(JmsReceiver.class);
        if (jmsReceiver != null) {
            jmsReceiver.stopReceiver();
            jmsReceiver.destroy();
        }
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        ((ConnectionManager)CaptainApplication.getInstance().getComponentManager().getBean(ConnectionManager.class)).closeConnection();
        contextManager.removeSession();
    }

    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        contextManager.addSession(((HttpServletRequest)sre.getServletRequest()).getSession(true));
        securityUtils.addSubject();
    }

    @Override
    public void sessionCreated(HttpSessionEvent se) { }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        securityUtils.removeSubject(se.getSession());
    }

}
